import tkinter as tk
from tkinter import filedialog, messagebox
from PIL import Image, ImageTk
import os
import numpy as np
import cv2
import json
import logging

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler("image_processor.log"),
        logging.StreamHandler()
    ]
)

# 语言配置数据
LANGUAGE_DATA = {
    "en": {
        "app_title": "Image Processor",
        "file": "File",
        "open_original": "Open Original",
        "open_grayscale": "Open as Grayscale",
        "merge_channels": "Merge Channels",
        "save_image": "Save Image",
        "exit": "Exit",
        "language": "Language",
        "info": "Info",
        "details": "Image Details",
        "edit": "Edit",
        "crop": "Crop",
        "reset": "Reset",
        "brightness_adjust": "Adjust Brightness",
        "split": "Split",
        "split_channels": "Split Channels",
        "channel_title": "Channel {}",
        "save_channel": "Save Channel",
        "error": "Error",
        "no_image_loaded": "No image loaded",
        "single_channel_error": "Image has only one channel",
        "single_file_error": "Please select multiple files",
        "info_str": "Filename: {}\nTotal Pixels: {}\nShape: {}\nChannels: {}\nData Type: {}",
        "no_image_to_be_saved": "No image to save",
        "no_image_to_be_cropped": "No image to crop",
        "no_crop_area": "No crop area selected",
        "crop_failed": "Crop failed",
        "no_reset_image": "No image to reset",
        "no_image_to_be_adjusted": "No image to adjust",
        "brightness_value": "Brightness: ",
        "apply": "Apply",
        "confirm_restart": "Confirm Restart",
        "restart_warning": "The application will restart to apply language changes. Continue?",
        "success": "Success",
        "channel_saved": "Channel {} saved to {}",
        "mask_saved": "Mask saved to {}",
        "and_operation_applied": "AND operation applied successfully",
        "not_operation_applied": "NOT operation applied successfully",
        "mask_loaded": "Mask loaded successfully",
        "mask_size_mismatch": "Mask size does not match current image",
        "not_color_image": "Color mask requires a color image",
        "color_mask": "Color Mask",
        "mask_operation": "Mask Operations",
        "load_mask": "Load Mask",
        "red_mask": "Red Mask",
        "green_mask": "Green Mask",
        "blue_mask": "Blue Mask",
        "threshold_processing": "Threshold Processing",
        "edge_detection": "Edge Detection",
        "shift_difference": "Shift Difference"
    },
    "zh": {
        "app_title": "图像处理工具",
        "file": "文件",
        "open_original": "打开原图",
        "open_grayscale": "以灰度模式打开",
        "merge_channels": "合并通道",
        "save_image": "保存图像",
        "exit": "退出",
        "language": "语言",
        "info": "信息",
        "details": "图像详情",
        "edit": "编辑",
        "crop": "裁剪",
        "reset": "重置",
        "brightness_adjust": "调整亮度",
        "split": "分割",
        "split_channels": "分割通道",
        "channel_title": "通道 {}",
        "save_channel": "保存通道",
        "error": "错误",
        "no_image_loaded": "没有加载图像",
        "single_channel_error": "图像只有一个通道",
        "single_file_error": "请选择多个文件",
        "info_str": "文件名: {}\n总像素: {}\n形状: {}\n通道数: {}\n数据类型: {}",
        "no_image_to_be_saved": "没有图像可保存",
        "no_image_to_be_cropped": "没有图像可裁剪",
        "no_crop_area": "没有选择裁剪区域",
        "crop_failed": "裁剪失败",
        "no_reset_image": "没有图像可重置",
        "no_image_to_be_adjusted": "没有图像可调整",
        "brightness_value": "亮度: ",
        "apply": "应用",
        "confirm_restart": "确认重启",
        "restart_warning": "应用程序将重启以应用语言更改。是否继续？",
        "success": "成功",
        "channel_saved": "通道 {} 已保存到 {}",
        "mask_saved": "掩模已保存到 {}",
        "and_operation_applied": "与运算已成功应用",
        "not_operation_applied": "非运算已成功应用",
        "mask_loaded": "掩模已成功加载",
        "mask_size_mismatch": "掩模尺寸与当前图像不匹配",
        "not_color_image": "颜色掩模需要彩色图像",
        "color_mask": "颜色掩模",
        "mask_operation": "遮罩运算",
        "load_mask": "加载掩模",
        "red_mask": "红色掩模",
        "green_mask": "绿色掩模",
        "blue_mask": "蓝色掩模",
        "threshold_processing": "阈值处理",
        "edge_detection": "边缘检测",
        "shift_difference": "移动差分"
    }
}

class ImageProcessor:
    def __init__(self, master):
        """初始化ImageProcessor类的实例"""
        self.master = master
        
        # 加载已保存的语言设置或使用默认值
        self.current_language = self.load_language_setting()
        master.title(LANGUAGE_DATA[self.current_language]['app_title'])

        self.image = None
        self.image_path = ""
        self.mask = None
        self.rect_start_x = None
        self.rect_start_y = None
        self.rect_end_x = None
        self.rect_end_y = None
        self.is_drawing = False
        self.current_rect = None
        self.original_image = None  # 用于保存原始图像，便于撤销操作

        self.create_widgets()

    def load_language_setting(self):
        """加载已保存的语言设置"""
        try:
            if os.path.exists("settings.json"):
                with open("settings.json", "r") as f:
                    settings = json.load(f)
                    return settings.get("language", "en")
            return "en"  # 默认使用英文
        except Exception as e:
            logging.error(f"Failed to load language setting: {e}")
            return "en"

    def save_language_setting(self, language):
        """保存语言设置"""
        try:
            with open("settings.json", "w") as f:
                json.dump({"language": language}, f)
        except Exception as e:
            logging.error(f"Failed to save language setting: {e}")

    def create_widgets(self):
        """创建GUI组件"""
        # 创建菜单栏
        menubar = tk.Menu(self.master)
        self.master.config(menu=menubar)

        # 创建文件菜单
        file_menu = tk.Menu(menubar)
        file_menu.add_command(label=LANGUAGE_DATA[self.current_language]['open_original'], command=self.open_as_original)
        file_menu.add_command(label=LANGUAGE_DATA[self.current_language]['open_grayscale'], command=self.open_as_gray)
        file_menu.add_command(label=LANGUAGE_DATA[self.current_language]['merge_channels'], command=self.merge_channels)
        file_menu.add_command(label=LANGUAGE_DATA[self.current_language]['save_image'], command=self.save_image)
        file_menu.add_separator()

        # 创建语言子菜单
        language_menu = tk.Menu(file_menu)
        self.language_var = tk.StringVar(value=self.current_language)
        language_menu.add_radiobutton(label="中文", variable=self.language_var, value="zh", command=self.change_language)
        language_menu.add_radiobutton(label="English", variable=self.language_var, value="en", command=self.change_language)
        file_menu.add_cascade(label=LANGUAGE_DATA[self.current_language]['language'], menu=language_menu)

        file_menu.add_command(label=LANGUAGE_DATA[self.current_language]['exit'], command=self.master.quit)
        menubar.add_cascade(label=LANGUAGE_DATA[self.current_language]['file'], menu=file_menu)

        # 创建信息菜单
        info_menu = tk.Menu(menubar)
        info_menu.add_command(label=LANGUAGE_DATA[self.current_language]['details'], command=self.show_image_details)
        menubar.add_cascade(label=LANGUAGE_DATA[self.current_language]['info'], menu=info_menu)

        # 创建编辑菜单
        edit_menu = tk.Menu(menubar)
        edit_menu.add_command(label=LANGUAGE_DATA[self.current_language]['crop'], command=self.crop_image)
        edit_menu.add_command(label=LANGUAGE_DATA[self.current_language]['reset'], command=self.reset_image)
        edit_menu.add_command(label=LANGUAGE_DATA[self.current_language]['brightness_adjust'], command=self.adjust_brightness)
        menubar.add_cascade(label=LANGUAGE_DATA[self.current_language]['edit'], menu=edit_menu)

        # 创建图像分割菜单
        split_menu = tk.Menu(menubar)
        menubar.add_cascade(label=LANGUAGE_DATA[self.current_language]['split'], menu=split_menu)
        split_menu.add_command(label=LANGUAGE_DATA[self.current_language]['split_channels'], command=self.split_image_channels)

        # 创建阈值处理菜单
        threshold_menu = tk.Menu(menubar)
        menubar.add_cascade(label=LANGUAGE_DATA[self.current_language]['threshold_processing'], menu=threshold_menu)
        threshold_menu.add_command(label="全局阈值处理", command=self.global_threshold)

        # 创建边缘菜单
        edge_menu = tk.Menu(menubar)
        menubar.add_cascade(label=LANGUAGE_DATA[self.current_language]['edge_detection'], menu=edge_menu)
        edge_menu.add_command(label=LANGUAGE_DATA[self.current_language]['shift_difference'], command=self.shift_difference)

        # 创建颜色掩模菜单
        color_mask_menu = tk.Menu(menubar)
        menubar.add_cascade(label=LANGUAGE_DATA[self.current_language]['color_mask'], menu=color_mask_menu)
        color_mask_menu.add_command(label="生成红色掩模", command=self.generate_red_mask)
        color_mask_menu.add_command(label="生成绿色掩模", command=self.generate_green_mask)
        color_mask_menu.add_command(label="生成蓝色掩模", command=self.generate_blue_mask)

        # 创建遮罩运算菜单
        mask_op_menu = tk.Menu(menubar)
        menubar.add_cascade(label=LANGUAGE_DATA[self.current_language]['mask_operation'], menu=mask_op_menu)
        mask_op_menu.add_command(label=LANGUAGE_DATA[self.current_language]['load_mask'], command=self.load_mask)
        mask_op_menu.add_command(label="与运算", command=self.apply_and_mask)
        mask_op_menu.add_command(label="非运算", command=self.apply_not_operation)

        # 创建图像显示区域
        self.canvas = tk.Canvas(self.master, width=600, height=400)
        self.canvas.pack()

        self.canvas.bind("<Button-1>", self.on_mouse_down)
        self.canvas.bind("<B1-Motion>", self.on_mouse_move)
        self.canvas.bind("<ButtonRelease-1>", self.on_mouse_up)

    def change_language(self):
        """切换语言"""
        new_language = self.language_var.get()
        if new_language != self.current_language:
            self.current_language = new_language
            self.save_language_setting(new_language)
            confirm = messagebox.askyesno(
                LANGUAGE_DATA[self.current_language]['confirm_restart'],
                LANGUAGE_DATA[self.current_language]['restart_warning']
            )
            if confirm:
                self.master.destroy()
                # 重新启动应用程序
                root = tk.Tk()
                app = ImageProcessor(root)
                root.mainloop()

    def merge_channels(self):
        """合并多个单通道图像为一个多通道图像"""
        file_paths = filedialog.askopenfilenames()
        if not file_paths:
            return

        if len(file_paths) == 1:
            messagebox.showerror(
                LANGUAGE_DATA[self.current_language]['error'],
                LANGUAGE_DATA[self.current_language]['single_file_error']
            )
            return

        try:
            # 合并通道逻辑
            channels = []
            for path in file_paths:
                img = cv2.imread(path, 0)  # 以灰度模式读取
                if img is not None:
                    channels.append(img)
            
            if len(channels) == 3:  # 通常是RGB三通道
                self.image = cv2.merge(channels)
                self.image = cv2.cvtColor(self.image, cv2.COLOR_BGR2RGB)  # 转换为RGB
                self.display_image()
            else:
                messagebox.showerror(
                    LANGUAGE_DATA[self.current_language]['error'],
                    "需要选择三个通道图像进行合并"
                )

        except Exception as e:
            messagebox.showerror(
                LANGUAGE_DATA[self.current_language]['error'],
                str(e)
            )

    def split_image_channels(self):
        """分割当前图像的通道"""
        if self.image is None:
            messagebox.showinfo(
                LANGUAGE_DATA[self.current_language]['error'],
                LANGUAGE_DATA[self.current_language]['no_image_loaded']
            )
            return

        if len(self.image.shape) == 2:
            messagebox.showinfo(
                LANGUAGE_DATA[self.current_language]['error'],
                LANGUAGE_DATA[self.current_language]['single_channel_error']
            )
            return

        try:
            if len(self.image.shape) == 3:
                channels = cv2.split(self.image)
                channel_names = ['R', 'G', 'B']
            else:
                channels = [self.image]
                channel_names = ['Gray']

            for i, channel in enumerate(channels):
                window = tk.Toplevel(self.master)
                window.title(LANGUAGE_DATA[self.current_language]['channel_title'].format(channel_names[i]))
                canvas = tk.Canvas(window, width=300, height=300)
                canvas.pack()

                def save_channel(channel=channel, name=channel_names[i]):
                    save_path = filedialog.asksaveasfilename(defaultextension=".png")
                    if save_path:
                        cv2.imwrite(save_path, channel)
                        messagebox.showinfo(
                            LANGUAGE_DATA[self.current_language]['success'],
                            LANGUAGE_DATA[self.current_language]['channel_saved'].format(name, save_path)
                        )

                save_button = tk.Button(window, text=LANGUAGE_DATA[self.current_language]['save_channel'], command=save_channel)
                save_button.pack()

                # 显示通道图像
                img = Image.fromarray(channel)
                img_tk = ImageTk.PhotoImage(img)
                canvas.create_image(0, 0, anchor=tk.NW, image=img_tk)
                canvas.image = img_tk

        except Exception as e:
            messagebox.showinfo(
                LANGUAGE_DATA[self.current_language]['error'],
                str(e)
            )

    def show_image_details(self):
        """显示当前图像的详细信息"""
        if self.image is None:
            messagebox.showinfo(
                LANGUAGE_DATA[self.current_language]['error'],
                LANGUAGE_DATA[self.current_language]['no_image_loaded']
            )
            return

        filename = os.path.basename(self.image_path)
        total_pixels = self.image.size
        shape = self.image.shape
        channels = shape[2] if len(shape) == 3 else 1
        dtype = self.image.dtype

        details = LANGUAGE_DATA[self.current_language]['info_str'].format(
            filename, total_pixels, shape, channels, dtype
        )

        messagebox.showinfo("INFO", details)

    def on_mouse_down(self, event):
        """处理鼠标左键按下事件"""
        if self.current_rect and not self.is_drawing:
            self.canvas.delete(self.current_rect)
            self.current_rect = None
        else:
            self.rect_start_x = event.x
            self.rect_start_y = event.y
            self.is_drawing = True

    def on_mouse_move(self, event):
        """处理鼠标左键移动事件"""
        if self.is_drawing:
            if self.current_rect:
                self.canvas.delete(self.current_rect)
            self.current_rect = self.canvas.create_rectangle(
                self.rect_start_x, self.rect_start_y, event.x, event.y, outline="red"
            )

    def on_mouse_up(self, event):
        """处理鼠标左键释放事件"""
        self.rect_end_x, self.rect_end_y = event.x, event.y
        self.is_drawing = False
        self.crop_region = (
            min(self.rect_start_y, self.rect_end_y),
            max(self.rect_start_y, self.rect_end_y),
            min(self.rect_start_x, self.rect_end_x),
            max(self.rect_start_x, self.rect_end_x)
        )

    def open_as_original(self):
        """打开原始图像"""
        self.image_path = filedialog.askopenfilename()
        if not self.image_path:
            return
        self.image = cv2.imread(self.image_path)
        if self.image is not None:
            self.image = cv2.cvtColor(self.image, cv2.COLOR_BGR2RGB)
            self.original_image = self.image.copy()  # 保存原始图像
            self.display_image()

    def open_as_gray(self):
        """将原始图像转换为灰度图像"""
        self.image_path = filedialog.askopenfilename()
        if not self.image_path:
            return
        self.image = cv2.imread(self.image_path, 0)
        if self.image is not None:
            self.original_image = self.image.copy()  # 保存原始图像
            self.display_image()

    def display_image(self):
        """在主画布上显示当前图像"""
        if self.image is None:
            return

        if len(self.image.shape) == 3:
            img = Image.fromarray(self.image)
        else:
            img = Image.fromarray(self.image, mode='L')

        canvas_width = self.canvas.winfo_width()
        canvas_height = self.canvas.winfo_height()
        img_width, img_height = img.size
        scale = min(canvas_width / img_width, canvas_height / img_height)

        if scale < 1:
            img = img.resize((int(img_width * scale), int(img_height * scale)), Image.LANCZOS)
        else:
            img = img.resize((int(img_width * scale), int(img_height * scale)), Image.BICUBIC)

        photo = ImageTk.PhotoImage(img)
        self.canvas.delete("all")
        x = (canvas_width - img.width) // 2
        y = (canvas_height - img.height) // 2
        self.canvas.create_image(x, y, anchor=tk.NW, image=photo)
        self.canvas.image = photo

    def save_image(self):
        """保存当前图像"""
        if self.image is None:
            messagebox.showinfo(
                LANGUAGE_DATA[self.current_language]['error'],
                LANGUAGE_DATA[self.current_language]['no_image_to_be_saved']
            )
            return

        save_path = filedialog.asksaveasfilename(defaultextension=".png")
        if not save_path:
            return

        if len(self.image.shape) == 3:
            img = cv2.cvtColor(self.image, cv2.COLOR_RGB2BGR)
        else:
            img = self.image

        cv2.imwrite(save_path, img)

    def crop_image(self):
        """裁剪当前图像"""
        if self.image is None:
            messagebox.showinfo(
                LANGUAGE_DATA[self.current_language]['error'],
                LANGUAGE_DATA[self.current_language]['no_image_to_be_cropped']
            )
            return

        if hasattr(self, 'crop_region') and self.current_rect:
            image_height, image_width = self.image.shape[:2]
            canvas_width = self.canvas.winfo_width()
            canvas_height = self.canvas.winfo_height()
            scale = min(canvas_width / image_width, canvas_height / image_height)
            offset_x = (canvas_width - image_width * scale) // 2
            offset_y = (canvas_height - image_height * scale) // 2

            real_crop_region = (
                int((self.crop_region[0] - offset_y) / scale),
                int((self.crop_region[1] - offset_y) / scale),
                int((self.crop_region[2] - offset_x) / scale),
                int((self.crop_region[3] - offset_x) / scale)
            )

            try:
                y1, y2, x1, x2 = real_crop_region
                self.image = self.image[y1:y2, x1:x2]
                self.display_image()
                self.canvas.delete(self.current_rect)
                self.current_rect = None
                delattr(self, 'crop_region')
            except:
                messagebox.showinfo(
                    LANGUAGE_DATA[self.current_language]['error'],
                    LANGUAGE_DATA[self.current_language]['crop_failed']
                )
        else:
            messagebox.showinfo(
                LANGUAGE_DATA[self.current_language]['error'],
                LANGUAGE_DATA[self.current_language]['no_crop_area']
            )

    def reset_image(self):
        """重置当前图像为原始状态"""
        if self.original_image is None:
            messagebox.showinfo(
                LANGUAGE_DATA[self.current_language]['error'],
                LANGUAGE_DATA[self.current_language]['no_reset_image']
            )
            return

        self.image = self.original_image.copy()
        self.display_image()

    def adjust_brightness(self):
        """调节图像亮度"""
        if self.image is None:
            messagebox.showinfo(
                LANGUAGE_DATA[self.current_language]['error'],
                LANGUAGE_DATA[self.current_language]['no_image_to_be_adjusted']
            )
            return

        self.original_image = self.image.copy()

        brightness_window = tk.Toplevel(self.master)
        brightness_window.title(LANGUAGE_DATA[self.current_language]['brightness_adjust'])
        brightness_window.geometry("300x150")
        brightness_window.resizable(False, False)

        brightness_label = tk.Label(
            brightness_window,
            text=LANGUAGE_DATA[self.current_language]['brightness_value'] + " 100%"
        )
        brightness_label.pack(pady=10)

        brightness_scale = tk.Scale(
            brightness_window, from_=0, to=200, orient=tk.HORIZONTAL, length=250, resolution=1
        )
        brightness_scale.set(100)
        brightness_scale.pack(pady=10)

        def apply_brightness(event=None):
            brightness_percent = brightness_scale.get()
            brightness_factor = brightness_percent / 100.0

            if brightness_factor == 1.0:
                self.image = self.original_image.copy()
            else:
                if len(self.original_image.shape) == 3:
                    img_hsv = cv2.cvtColor(self.original_image, cv2.COLOR_RGB2HSV)
                    img_hsv[:, :, 2] = np.clip(img_hsv[:, :, 2] * brightness_factor, 0, 255).astype(np.uint8)
                    self.image = cv2.cvtColor(img_hsv, cv2.COLOR_HSV2RGB)
                else:
                    self.image = np.clip(self.original_image * brightness_factor, 0, 255).astype(np.uint8)

            brightness_label.config(
                text=LANGUAGE_DATA[self.current_language]['brightness_value'] + f" {brightness_percent}%"
            )
            self.display_image()

        brightness_scale.bind("<Motion>", apply_brightness)
        brightness_scale.bind("<ButtonRelease-1>", apply_brightness)

        button_frame = tk.Frame(brightness_window)
        button_frame.pack(pady=10)

        apply_button = tk.Button(
            button_frame, text=LANGUAGE_DATA[self.current_language]['apply'],
            command=lambda: brightness_window.destroy()
        )
        apply_button.pack(side=tk.LEFT, padx=10)

        cancel_button = tk.Button(
            button_frame, text="取消",
            command=lambda: cancel_brightness()
        )
        cancel_button.pack(side=tk.LEFT, padx=10)

        def cancel_brightness():
            self.image = self.original_image.copy()
            self.display_image()
            brightness_window.destroy()

        brightness_window.protocol("WM_DELETE_WINDOW", cancel_brightness)

    def global_threshold(self):
        """全局阈值处理"""
        if self.image is None:
            messagebox.showinfo(
                LANGUAGE_DATA[self.current_language]['error'],
                LANGUAGE_DATA[self.current_language]['no_image_loaded']
            )
            return

        if len(self.image.shape) == 3:
            messagebox.showerror("错误", "阈值处理只能应用于灰度图像。请先将图像转换为灰度模式。")
            return

        self.original_image = self.image.copy()

        threshold_window = tk.Toplevel(self.master)
        threshold_window.title("全局阈值处理")
        threshold_window.geometry("300x180")
        threshold_window.resizable(False, False)

        threshold_label = tk.Label(threshold_window, text="阈值: 127")
        threshold_label.pack(pady=10)

        threshold_scale = tk.Scale(
            threshold_window, from_=0, to=255, orient=tk.HORIZONTAL, length=250, resolution=1
        )
        threshold_scale.set(127)
        threshold_scale.pack(pady=10)

        def apply_threshold(event=None):
            threshold = threshold_scale.get()
            _, self.image = cv2.threshold(self.original_image, threshold, 255, cv2.THRESH_BINARY)
            threshold_label.config(text=f"阈值: {threshold}")
            self.display_image()

        threshold_scale.bind("<Motion>", apply_threshold)
        threshold_scale.bind("<ButtonRelease-1>", apply_threshold)

        button_frame = tk.Frame(threshold_window)
        button_frame.pack(pady=10)

        apply_button = tk.Button(
            button_frame, text="应用",
            command=lambda: threshold_window.destroy()
        )
        apply_button.pack(side=tk.LEFT, padx=10)

        cancel_button = tk.Button(
            button_frame, text="取消",
            command=lambda: cancel_threshold()
        )
        cancel_button.pack(side=tk.LEFT, padx=10)

        def cancel_threshold():
            self.image = self.original_image.copy()
            self.display_image()
            threshold_window.destroy()

        threshold_window.protocol("WM_DELETE_WINDOW", cancel_threshold)

    def shift_difference(self):
        """移动差分边缘检测"""
        if self.image is None:
            messagebox.showinfo(
                LANGUAGE_DATA[self.current_language]['error'],
                LANGUAGE_DATA[self.current_language]['no_image_loaded']
            )
            return

        if len(self.image.shape) == 3:
            messagebox.showerror("错误", "边缘检测只能应用于灰度图像。请先将图像转换为灰度模式。")
            return

        self.original_image = self.image.copy()

        edge_window = tk.Toplevel(self.master)
        edge_window.title("移动差分边缘检测")
        edge_window.geometry("350x180")
        edge_window.resizable(False, False)

        shift_label = tk.Label(edge_window, text="像素偏移: 0")
        shift_label.pack(pady=10)

        shift_scale = tk.Scale(
            edge_window, from_=-3, to=3, orient=tk.HORIZONTAL, length=300, resolution=1
        )
        shift_scale.set(0)
        shift_scale.pack(pady=10)

        def apply_shift_difference(event=None):
            shift = shift_scale.get()

            if shift == 0:
                self.image = np.zeros_like(self.original_image)
            else:
                shifted = np.zeros_like(self.original_image)

                if shift > 0:
                    shifted[:, shift:] = self.original_image[:, :-shift]
                else:
                    shifted[:, :shift] = self.original_image[:, -shift:]

                diff = np.abs(self.original_image.astype(np.int16) - shifted.astype(np.int16))
                self.image = np.clip(diff, 0, 255).astype(np.uint8)

            direction = "右" if shift > 0 else "左"
            shift_label.config(text=f"像素偏移: {abs(shift)} 像素 ({direction})")
            self.display_image()

        shift_scale.bind("<Motion>", apply_shift_difference)
        shift_scale.bind("<ButtonRelease-1>", apply_shift_difference)

        button_frame = tk.Frame(edge_window)
        button_frame.pack(pady=10)

        apply_button = tk.Button(
            button_frame, text="应用",
            command=lambda: edge_window.destroy()
        )
        apply_button.pack(side=tk.LEFT, padx=10)

        cancel_button = tk.Button(
            button_frame, text="取消",
            command=lambda: cancel_edge()
        )
        cancel_button.pack(side=tk.LEFT, padx=10)

        def cancel_edge():
            self.image = self.original_image.copy()
            self.display_image()
            edge_window.destroy()

        edge_window.protocol("WM_DELETE_WINDOW", cancel_edge)

    def generate_red_mask(self):
        """生成红色掩模"""
        self.generate_color_mask(2)  # 红色通道索引为2（BGR格式）

    def generate_green_mask(self):
        """生成绿色通道掩模"""
        self.generate_color_mask(1)  # 绿色通道索引为1

    def generate_blue_mask(self):
        """生成蓝色通道掩模"""
        self.generate_color_mask(0)  # 蓝色通道索引为0

    def generate_color_mask(self, channel_index):
        """通用颜色掩模生成方法"""
        if self.image is None:
            messagebox.showerror(
                LANGUAGE_DATA[self.current_language]['error'],
                LANGUAGE_DATA[self.current_language]['no_image_loaded']
            )
            return

        if len(self.image.shape) != 3:
            messagebox.showerror(
                LANGUAGE_DATA[self.current_language]['error'],
                LANGUAGE_DATA[self.current_language]['not_color_image']
            )
            return

        # 确保图像是RGB格式
        rgb_image = self.image if len(self.image.shape) == 3 else cv2.cvtColor(self.image, cv2.COLOR_GRAY2RGB)
        
        # 创建颜色掩模
        mask = np.zeros_like(rgb_image)
        
        # 生成掩模 - 将选定通道的强度映射到对应颜色通道
        if channel_index == 0:  # 蓝色
            mask[:,:,0] = rgb_image[:,:,0]
        elif channel_index == 1:  # 绿色
            mask[:,:,1] = rgb_image[:,:,1]
        else:  # 红色
            mask[:,:,2] = rgb_image[:,:,2]
        
        # 创建显示窗口
        self.create_mask_window(mask, f"{LANGUAGE_DATA[self.current_language]['color_mask']} {['蓝', '绿', '红'][channel_index]}")

    def create_mask_window(self, mask_image, title):
        """创建掩模显示窗口"""
        window = tk.Toplevel(self.master)
        window.title(title)
        canvas = tk.Canvas(window, width=600, height=400)
        canvas.pack()

        # 显示图像
        img = Image.fromarray(mask_image)
        canvas_width = canvas.winfo_width()
        canvas_height = canvas.winfo_height()
        img_width, img_height = img.size
        scale = min(canvas_width / img_width, canvas_height / img_height)

        if scale < 1:
            img = img.resize((int(img_width * scale), int(img_height * scale)), Image.LANCZOS)
        else:
            img = img.resize((int(img_width * scale), int(img_height * scale)), Image.BICUBIC)

        photo = ImageTk.PhotoImage(img)
        x = (canvas_width - img.width) // 2
        y = (canvas_height - img.height) // 2
        canvas.create_image(x, y, anchor=tk.NW, image=photo)
        canvas.image = photo

        # 保存按钮
        save_button = tk.Button(
            window, 
            text="保存掩模", 
            command=lambda: self.save_mask(mask_image)
        )
        save_button.pack(pady=5)

        self.mask = mask_image  # 保存掩模到实例变量

    def save_mask(self, mask_image):
        """保存掩模图像"""
        save_path = filedialog.asksaveasfilename(defaultextension=".png")
        if not save_path:
            return
        # 确保保存时使用BGR格式
        bgr_mask = cv2.cvtColor(mask_image, cv2.COLOR_RGB2BGR) if len(mask_image.shape) == 3 else mask_image
        cv2.imwrite(save_path, bgr_mask)
        messagebox.showinfo(
            LANGUAGE_DATA[self.current_language]['success'],
            LANGUAGE_DATA[self.current_language]['mask_saved'].format(save_path)
        )
        self.mask = cv2.imread(save_path)  # 保存后重新加载掩模

    def load_mask(self):
        """加载掩模图像"""
        file_path = filedialog.askopenfilename(
            filetypes=[("图像文件", "*.png;*.jpg;*.jpeg")]
        )
        if not file_path:
            return

        try:
            self.mask = cv2.imread(file_path)
            if self.mask is None:
                messagebox.showerror(
                    LANGUAGE_DATA[self.current_language]['error'],
                    "无法加载掩模图像"
                )
                return

            # 转换为RGB格式
            if len(self.mask.shape) == 3:
                self.mask = cv2.cvtColor(self.mask, cv2.COLOR_BGR2RGB)

            messagebox.showinfo(
                LANGUAGE_DATA[self.current_language]['success'],
                LANGUAGE_DATA[self.current_language]['mask_loaded']
            )

        except Exception as e:
            messagebox.showerror(
                LANGUAGE_DATA[self.current_language]['error'],
                f"加载掩模失败: {str(e)}"
            )

    def apply_and_mask(self):
        """应用与运算遮罩"""
        if self.image is None:
            messagebox.showerror(
                LANGUAGE_DATA[self.current_language]['error'],
                LANGUAGE_DATA[self.current_language]['no_image_loaded']
            )
            return

        if self.mask is None:
            messagebox.showerror(
                LANGUAGE_DATA[self.current_language]['error'],
                "没有加载掩模，请先加载或生成掩模"
            )
            return

        # 确保掩模与图像尺寸一致
        if self.image.shape[:2] != self.mask.shape[:2]:
            messagebox.showerror(
                LANGUAGE_DATA[self.current_language]['error'],
                LANGUAGE_DATA[self.current_language]['mask_size_mismatch']
            )
            return

        try:
            # 处理不同通道数的情况
            if len(self.image.shape) == 3 and len(self.mask.shape) == 3:
                # 两个都是彩色图像
                self.image = cv2.bitwise_and(self.image, self.mask)
            elif len(self.image.shape) == 3 and len(self.mask.shape) == 2:
                # 图像是彩色，掩模是灰度
                # 将灰度掩模扩展为三通道
                mask_3d = cv2.cvtColor(self.mask, cv2.COLOR_GRAY2RGB)
                self.image = cv2.bitwise_and(self.image, mask_3d)
            elif len(self.image.shape) == 2 and len(self.mask.shape) == 3:
                # 图像是灰度，掩模是彩色
                # 取掩模的第一个通道作为灰度掩模
                gray_mask = self.mask[:,:,0]
                self.image = cv2.bitwise_and(self.image, gray_mask)
            else:
                # 两个都是灰度图像
                self.image = cv2.bitwise_and(self.image, self.mask)

            self.display_image()
            messagebox.showinfo(
                LANGUAGE_DATA[self.current_language]['success'],
                LANGUAGE_DATA[self.current_language]['and_operation_applied']
            )

        except Exception as e:
            messagebox.showerror(
                LANGUAGE_DATA[self.current_language]['error'],
                f"应用与运算失败: {str(e)}"
            )

    def apply_not_operation(self):
        """应用非运算"""
        if self.image is None:
            messagebox.showerror(
                LANGUAGE_DATA[self.current_language]['error'],
                LANGUAGE_DATA[self.current_language]['no_image_loaded']
            )
            return

        try:
            if len(self.image.shape) == 3:
                self.image = cv2.bitwise_not(self.image)
            else:
                self.image = cv2.bitwise_not(self.image)

            self.display_image()
            messagebox.showinfo(
                LANGUAGE_DATA[self.current_language]['success'],
                LANGUAGE_DATA[self.current_language]['not_operation_applied']
            )

        except Exception as e:
            messagebox.showerror(
                LANGUAGE_DATA[self.current_language]['error'],
                f"应用非运算失败: {str(e)}"
            )

if __name__ == "__main__":
    root = tk.Tk()
    app = ImageProcessor(root)
    root.mainloop()